home *** CD-ROM | disk | FTP | other *** search
/ 100 Best Shareware & Freeware Games / 100 Games.iso / Cards / PySol / pysol460.exe / {app} / python / DLLs / tk8.3 / safetk.tcl < prev    next >
Encoding:
Text File  |  2001-07-27  |  7.1 KB  |  273 lines

  1. # safetk.tcl --
  2. #
  3. # Support procs to use Tk in safe interpreters.
  4. #
  5. # RCS: @(#) $Id: safetk.tcl,v 1.6 2000/04/08 06:59:28 hobbs Exp $
  6. #
  7. # Copyright (c) 1997 Sun Microsystems, Inc.
  8. #
  9. # See the file "license.terms" for information on usage and redistribution
  10. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  
  12. # see safetk.n for documentation
  13.  
  14. #
  15. #
  16. # Note: It is now ok to let untrusted code being executed
  17. #       between the creation of the interp and the actual loading
  18. #       of Tk in that interp because the C side Tk_Init will
  19. #       now look up the master interp and ask its safe::TkInit
  20. #       for the actual parameters to use for it's initialization (if allowed),
  21. #       not relying on the slave state.
  22. #
  23.  
  24. # We use opt (optional arguments parsing)
  25. package require opt 0.4.1;
  26.  
  27. namespace eval ::safe {
  28.  
  29.     # counter for safe toplevels
  30.     variable tkSafeId 0;
  31.  
  32.     #
  33.     # tkInterpInit : prepare the slave interpreter for tk loading
  34.     #                most of the real job is done by loadTk
  35.     # returns the slave name (tkInterpInit does)
  36.     #
  37.     proc ::safe::tkInterpInit {slave argv} {
  38.     global env tk_library
  39.  
  40.     # Clear Tk's access for that interp (path).
  41.     allowTk $slave $argv
  42.  
  43.     # there seems to be an obscure case where the tk_library
  44.     # variable value is changed to point to a sym link destination
  45.     # dir instead of the sym link itself, and thus where the $tk_library
  46.     # would then not be anymore one of the auto_path dir, so we use
  47.     # the addToAccessPath which adds if it's not already in instead
  48.     # of the more conventional findInAccessPath.
  49.     # Might be usefull for masters without Tk really loaded too.
  50.     ::interp eval $slave [list set tk_library [::safe::interpAddToAccessPath $slave $tk_library]]
  51.     return $slave
  52.     }
  53.  
  54.  
  55. # tkInterpLoadTk : 
  56. # Do additional configuration as needed (calling tkInterpInit) 
  57. # and actually load Tk into the slave.
  58. # Either contained in the specified windowId (-use) or
  59. # creating a decorated toplevel for it.
  60.  
  61. # empty definition for auto_mkIndex
  62. proc ::safe::loadTk {} {}
  63.    
  64. ::tcl::OptProc loadTk {
  65.     {slave -interp "name of the slave interpreter"}
  66.     {-use  -windowId {} "window Id to use (new toplevel otherwise)"}
  67.     {-display -displayName {} "display name to use (current one otherwise)"}
  68. } {
  69.     set displayGiven [::tcl::OptProcArgGiven "-display"]
  70.     if {!$displayGiven} {
  71.     
  72.     # Try to get the current display from "."
  73.     # (which might not exist if the master is tk-less)
  74.     
  75.     if {[catch {set display [winfo screen .]}]} {
  76.         if {[info exists ::env(DISPLAY)]} {
  77.         set display $::env(DISPLAY)
  78.         } else {
  79.         Log $slave "no winfo screen . nor env(DISPLAY)" WARNING
  80.         set display ":0.0"
  81.         }
  82.     }
  83.     }
  84.     if {![::tcl::OptProcArgGiven "-use"]} {
  85.     
  86.     # create a decorated toplevel
  87.     
  88.     ::tcl::Lassign [tkTopLevel $slave $display] w use
  89.  
  90.     # set our delete hook (slave arg is added by interpDelete)
  91.     # to clean up both window related code and tkInit(slave)
  92.     Set [DeleteHookName $slave] [list tkDelete {} $w]
  93.  
  94.     } else {
  95.  
  96.     # set our delete hook (slave arg is added by interpDelete)
  97.     # to clean up tkInit(slave)
  98.         
  99.     Set [DeleteHookName $slave] [list disallowTk]
  100.  
  101.     # Let's be nice and also accept tk window names instead of ids
  102.     
  103.     if {[string match ".*" $use]} {
  104.         set windowName $use
  105.         set use [winfo id $windowName]
  106.         set nDisplay [winfo screen $windowName]
  107.     } else {
  108.  
  109.         # Check for a better -display value
  110.         # (works only for multi screens on single host, but not
  111.         #  cross hosts, for that a tk window name would be better
  112.         #  but embeding is also usefull for non tk names)
  113.         
  114.         if {![catch {winfo pathname $use} name]} {
  115.         set nDisplay [winfo screen $name]
  116.         } else {
  117.  
  118.         # Can't have a better one
  119.         
  120.         set nDisplay $display
  121.         }
  122.     }
  123.     if {[string compare $nDisplay $display]} {
  124.         if {$displayGiven} {
  125.         error "conflicting -display $display and -use\
  126.             $use -> $nDisplay"
  127.         } else {
  128.         set display $nDisplay
  129.         }
  130.     }
  131.     }
  132.  
  133.     # Prepares the slave for tk with those parameters
  134.     
  135.     tkInterpInit $slave [list "-use" $use "-display" $display]
  136.     
  137.     load {} Tk $slave
  138.  
  139.     return $slave
  140. }
  141.  
  142. proc ::safe::TkInit {interpPath} {
  143.     variable tkInit
  144.     if {[info exists tkInit($interpPath)]} {
  145.     set value $tkInit($interpPath)
  146.     Log $interpPath "TkInit called, returning \"$value\"" NOTICE
  147.     return $value
  148.     } else {
  149.     Log $interpPath "TkInit called for interp with clearance:\
  150.         preventing Tk init" ERROR
  151.     error "not allowed"
  152.     }
  153. }
  154.  
  155. # safe::allowTk --
  156. #
  157. #    Set tkInit(interpPath) to allow Tk to be initialized in
  158. #    safe::TkInit.
  159. #
  160. # Arguments:
  161. #    interpPath    slave interpreter handle
  162. #    argv        arguments passed to safe::TkInterpInit
  163. #
  164. # Results:
  165. #    none.
  166.  
  167. proc ::safe::allowTk {interpPath argv} {
  168.     variable tkInit
  169.     set tkInit($interpPath) $argv
  170.     return
  171. }
  172.  
  173.  
  174. # safe::disallowTk --
  175. #
  176. #    Unset tkInit(interpPath) to disallow Tk from getting initialized
  177. #    in safe::TkInit.
  178. #
  179. # Arguments:
  180. #    interpPath    slave interpreter handle
  181. #
  182. # Results:
  183. #    none.
  184.  
  185. proc ::safe::disallowTk {interpPath} {
  186.     variable tkInit
  187.     # This can already be deleted by the DeleteHook of the interp
  188.     if {[info exists tkInit($interpPath)]} {
  189.     unset tkInit($interpPath)
  190.     }
  191.     return
  192. }
  193.  
  194.  
  195. # safe::tkDelete --
  196. #
  197. #    Clean up the window associated with the interp being deleted.
  198. #
  199. # Arguments:
  200. #    interpPath    slave interpreter handle
  201. #
  202. # Results:
  203. #    none.
  204.  
  205. proc ::safe::tkDelete {W window slave} {
  206.  
  207.     # we are going to be called for each widget... skip untill it's
  208.     # top level
  209.  
  210.     Log $slave "Called tkDelete $W $window" NOTICE
  211.     if {[::interp exists $slave]} {
  212.     if {[catch {::safe::interpDelete $slave} msg]} {
  213.         Log $slave "Deletion error : $msg"
  214.     }
  215.     }
  216.     if {[winfo exists $window]} {
  217.     Log $slave "Destroy toplevel $window" NOTICE
  218.     destroy $window
  219.     }
  220.     
  221.     # clean up tkInit(slave)
  222.     disallowTk $slave
  223.     return
  224. }
  225.  
  226. proc ::safe::tkTopLevel {slave display} {
  227.     variable tkSafeId
  228.     incr tkSafeId
  229.     set w ".safe$tkSafeId"
  230.     if {[catch {toplevel $w -screen $display -class SafeTk} msg]} {
  231.     return -code error "Unable to create toplevel for\
  232.         safe slave \"$slave\" ($msg)"
  233.     }
  234.     Log $slave "New toplevel $w" NOTICE
  235.  
  236.     set msg "Untrusted Tcl applet ($slave)"
  237.     wm title $w $msg
  238.  
  239.     # Control frame
  240.     set wc $w.fc
  241.     frame $wc -bg red -borderwidth 3 -relief ridge
  242.  
  243.     # We will destroy the interp when the window is destroyed
  244.     bindtags $wc [concat Safe$wc [bindtags $wc]]
  245.     bind Safe$wc <Destroy> [list ::safe::tkDelete %W $w $slave]
  246.  
  247.     label $wc.l -text $msg -padx 2 -pady 0 -anchor w
  248.  
  249.     # We want the button to be the last visible item
  250.     # (so be packed first) and at the right and not resizing horizontally
  251.  
  252.     # frame the button so it does not expand horizontally
  253.     # but still have the default background instead of red one from the parent
  254.     frame  $wc.fb -bd 0
  255.     button $wc.fb.b -text "Delete" \
  256.         -bd 1  -padx 2 -pady 0 -highlightthickness 0 \
  257.         -command [list ::safe::tkDelete $w $w $slave]
  258.     pack $wc.fb.b -side right -fill both
  259.     pack $wc.fb -side right -fill both -expand 1
  260.     pack $wc.l -side left  -fill both -expand 1
  261.     pack $wc -side bottom -fill x
  262.  
  263.     # Container frame
  264.     frame $w.c -container 1
  265.     pack $w.c -fill both -expand 1
  266.     
  267.     # return both the toplevel window name and the id to use for embedding
  268.     list $w [winfo id $w.c]
  269. }
  270.  
  271. }
  272.